package com.weilx959.spt.plugin.e2sp.controller;

import com.jfoenix.controls.JFXTextArea;
import com.weilx959.spt.core.StageContext;
import com.weilx959.spt.core.component.VDialog;
import com.weilx959.spt.core.component.VToast;
import com.weilx959.spt.core.constants.CommonConstants;
import com.weilx959.spt.core.factory.SingletonFactory;
import com.weilx959.spt.core.interfaces.Controller;
import com.weilx959.spt.core.utils.Try;
import com.weilx959.spt.plugin.e2sp.model.TransformedExcelVO;
import com.weilx959.spt.plugin.e2sp.model.statement.ErrorStatement;
import com.weilx959.spt.plugin.e2sp.service.SqlToExcelService;
import com.weilx959.spt.plugin.e2sp.utils.ResourceBundleUtil;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.FileChooser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

/**
 * SQL转Excel控制器
 *
 * @author weilx
 * @since 2024年7月6日
 */
@Slf4j
public class SqlToExcelController implements Controller {
    @FXML
    public GridPane rootPane;

    @FXML
    public Label sqlFileLabel;

    @FXML
    public JFXTextArea sqlTextArea;

    @FXML
    public AnchorPane sqlAnchorPane;

    private TransformedExcelVO transExcelVO;

    private String oldSql;

    private final ResourceBundle bundle = ResourceBundleUtil.get();

    @FXML
    private void initialize() {
        // do nothing
    }

    @Override
    public Pane getRootPane() {
        return rootPane;
    }

    @Override
    public void onShow(Map<String, Object> config) {
        // do nothing
    }

    @Override
    public boolean onClose() {
        return true;
    }

    @Override
    public boolean onDestroy() {
        return true;
    }

    /**
     * 1. 打开文件选择器，选择SQL文件
     * 2. 读取SQL文件内容并显示到文本框中
     *
     * @param event 鼠标点击事件
     */
    public void openButtonClicked(MouseEvent event) {
        event.consume();
        // 打开文件选择器
        var fileChooser = new FileChooser();
        fileChooser.setTitle(bundle.getString("s2e.main.chooser.title"));
        Optional.ofNullable(sqlFileLabel.getText())
            .filter(StringUtils::isNotBlank)
            .map(Paths::get)
            .map(Path::toFile)
            .map(File::getParentFile)
            .or(() -> Optional.of(Paths.get(CommonConstants.DEFAULT_APP_PATH).toFile()))
            .ifPresent(fileChooser::setInitialDirectory);
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(bundle.getString("s2s.main.chooser.typename"), "*.sql"));
        var file = fileChooser.showOpenDialog(StageContext.get());

        if (Objects.isNull(file) || file.isDirectory() || !file.exists()) {
            VToast.error(bundle.getString("s2e.main.message.file-not-choose"));
            return;
        }
        sqlFileLabel.setText(file.getAbsolutePath());
        sqlTextArea.clear();
        try {
            var lines = Files.readAllLines(file.toPath());
            sqlTextArea.setText(String.join("\n", lines));
        } catch (Exception e) {
            String msg = bundle.getString("s2e.main.message.file-read-failed");
            log.error(msg, e);
            VToast.error(msg + e.getMessage());
        }
    }

    /**
     * 将SQL文本框内容重写到文件中。
     * 如果没有选择文件，则弹出提示框。
     * 如果文本框内容为空，则弹出提示框。
     * 如果文件存在，则覆盖原文件。
     *
     * @param event 鼠标点击事件
     */
    public void saveButtonClicked(MouseEvent event) {
        event.consume();
        if (StringUtils.isBlank(sqlFileLabel.getText())) {
            VToast.error(bundle.getString("s2e.main.message.file-not-choose"));
            return;
        }
        if (StringUtils.isBlank(sqlTextArea.getText())) {
            VToast.error(bundle.getString("s2s.main.message.content-is-empty"));
            return;
        }
        try {
            Files.write(Paths.get(sqlFileLabel.getText()),
                sqlTextArea.getText().getBytes(), StandardOpenOption.TRUNCATE_EXISTING);
        } catch (Exception e) {
            String msg = bundle.getString("s2e.main.message.save-failed");
            log.error(msg, e);
            VToast.error(msg + e.getMessage());
        }
    }

    /**
     * 1. 如果SQL文本框内容为空，则弹出提示框。
     * 2. 弹出提示框，确认是否要转换SQL到Excel。
     * 3. 将SQL文本框内容按“;”分割。
     * 4. 调用格式化工具类，将SQL转换为语句对象
     * 5. 将语句对象转为EXCEL对象
     * 6. 调用EXCEL写入工具类，将EXCEL写入到文件中。
     *
     * @param event 鼠标点击事件
     */
    public void submitButtonClicked(MouseEvent event) {
        event.consume();
        if (StringUtils.isBlank(sqlTextArea.getText())) {
            VToast.error(bundle.getString("s2s.main.message.content-is-empty"));
            return;
        }
        if (!isSqlChanged()) {
            VToast.info(bundle.getString("s2e.main.message.content-not-modified"));
            return;
        }
        SqlToExcelService sqlToExcelService = SingletonFactory.getInstance(SqlToExcelService.class);
        VDialog.confirm(bundle.getString("s2e.main.message.submit-confirm"), dialog -> {
            dialog.close();
            Try.of(() -> {
                // 转换语句
                oldSql = sqlTextArea.getText();
                String tmpSql = sqlToExcelService.preDeal(oldSql);
                transExcelVO = sqlToExcelService.parseToExcelVO(tmpSql);
                return transExcelVO.getErrorStatements();
            }).map(v -> {
                if (CollectionUtils.isNotEmpty(v)) {
                    String errorSql = v.stream()
                        .map(ErrorStatement::getSql)
                        .map(String::trim)
                        .collect(Collectors.joining("\n"));
                    VDialog.alert(bundle.getString("s2e.main.message.submit-has-error") + "\n" + errorSql);
                }
                this.saveExcel();
                return null;
            }).failure(e -> {
                String msg = bundle.getString("s2e.main.message.submit-failed");
                log.error(msg, e);
                VToast.error(msg);
            }).success(v -> VToast.info(bundle.getString("s2e.main.message.submit-successful")
                + Paths.get(transExcelVO.getOutputDir(), transExcelVO.getName())));
        });
    }

    public void scrollToTop(ActionEvent event) {
        event.consume();
        sqlTextArea.setScrollTop(0);
    }

    public void scrollToBottom(ActionEvent event) {
        event.consume();
        sqlTextArea.setScrollTop(Double.MAX_VALUE);
    }

    public void toggleWrap(ActionEvent event) {
        event.consume();
        sqlTextArea.setWrapText(!sqlTextArea.isWrapText());
    }

    /**
     * 判断SQL文本框内容是否发生变化。
     *
     * @return true：内容发生变化；false：内容没有变化。
     */
    private boolean isSqlChanged() {
        return Objects.isNull(oldSql) || !Objects.equals(sqlTextArea.getText(), oldSql);
    }

    /**
     * 保存excel
     */
    private void saveExcel() {
        Path sqlPath = Paths.get(sqlFileLabel.getText());
        String fileName = sqlPath.toFile().getName();
        fileName = fileName.substring(0, fileName.lastIndexOf("."));
        fileName += ".xlsx";
        transExcelVO.setOutputDir(sqlPath.getParent().toString());
        transExcelVO.setName(fileName);
        SqlToExcelService sqlToExcelService = SingletonFactory.getInstance(SqlToExcelService.class);
        sqlToExcelService.exportExcel(transExcelVO);
    }
}
